package com.example.project.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.example.project.entity.Issue;
import com.example.project.entity.IssueSimilarityCache;
import com.example.project.mapper.IssueMapper;
import com.example.project.mapper.IssueSimilarityCacheMapper;
import com.example.project.service.IssueSimilarityService;
import com.example.project.utils.HanLPUtil;
import com.example.project.utils.SimilarTextUtil;
import com.example.project.utils.html.HtmlUtils;

/**
 * 需求相似度服务实现类
 */
@Service
public class IssueSimilarityServiceImpl implements IssueSimilarityService {

	@Autowired
	private IssueMapper issueMapper;

	@Autowired
	private IssueSimilarityCacheMapper similarityCacheMapper;

	// 相似度阈值
	private static final double SIMILARITY_THRESHOLD = 0.3;

	@Override
	public List<Issue> findSimilarIssues(Long issueId, Integer limit) {
		Issue sourceIssue = issueMapper.selectIssuesById(issueId);
		if (sourceIssue == null) {
			return new ArrayList<>();
		}

		// 先从缓存中查找
		List<IssueSimilarityCache> cachedResults = similarityCacheMapper.selectBySourceIssueId(issueId);

		// 如果缓存中有足够的结果，直接返回
		if (cachedResults.size() >= (limit != null ? limit : 5)) {
			List<Long> issueIds = cachedResults.stream()
					.filter(cache -> cache.getSimilarityScore().doubleValue() >= SIMILARITY_THRESHOLD)
					.sorted(Comparator.comparing(IssueSimilarityCache::getSimilarityScore).reversed())
					.limit(limit != null ? limit : 5).map(IssueSimilarityCache::getTargetIssueId)
					.collect(Collectors.toList());

			if (!issueIds.isEmpty()) {
				List<Issue> similarIssues = issueMapper.selectIssuesByIds(issueIds);
				// 按相似度分数排序
				Map<Long, BigDecimal> scoreMap = cachedResults.stream().collect(Collectors
						.toMap(IssueSimilarityCache::getTargetIssueId, IssueSimilarityCache::getSimilarityScore));

				return similarIssues.stream()
						.sorted((a, b) -> scoreMap.get(b.getId()).compareTo(scoreMap.get(a.getId())))
						.collect(Collectors.toList());
			}
		}

		// 缓存中没有或结果不足，实时计算
		return calculateSimilarIssues(sourceIssue, limit);
	}

	@Override
	@Transactional
	public void calculateAndCacheSimilarities(Long issueId) {
		Issue sourceIssue = issueMapper.selectIssuesById(issueId);
		if (sourceIssue == null) {
			return;
		}

		// 清除旧缓存
		similarityCacheMapper.deleteBySourceIssueId(issueId);

		// 获取同一项目的其他需求
		List<Issue> candidateIssues = issueMapper.selectCandidatesForSimilarity(issueId, sourceIssue.getProjectId());

		List<IssueSimilarityCache> caches = new ArrayList<>();

		for (Issue candidate : candidateIssues) {
			SimilarityResult result = calculateSimilarity(sourceIssue, candidate);

			if (result.getScore() >= SIMILARITY_THRESHOLD) {
				IssueSimilarityCache cache = new IssueSimilarityCache();
				cache.setSourceIssueId(issueId);
				cache.setTargetIssueId(candidate.getId());
				cache.setSimilarityScore(BigDecimal.valueOf(result.getScore()).setScale(4, RoundingMode.HALF_UP));
				cache.setMatchReasons(result.getReasons());
				caches.add(cache);
			}
		}

		// 按相似度排序并保存前20个
		caches.sort((a, b) -> b.getSimilarityScore().compareTo(a.getSimilarityScore()));
		List<IssueSimilarityCache> toSave = caches.stream().limit(20).collect(Collectors.toList());

		if (!toSave.isEmpty()) {
			similarityCacheMapper.batchInsert(toSave);
		}

		// 更新需求的关键词和标签
		updateKeywordsAndTags(sourceIssue);
	}

	@Override
	public void clearSimilarityCache(Long issueId) {
		similarityCacheMapper.deleteBySourceIssueId(issueId);
	}

	@Override
	public List<Issue> findSimilarIssuesByKeywords(String keywords, Long projectId, Integer limit) {
		if (!StringUtils.hasText(keywords)) {
			return new ArrayList<>();
		}

		// 分割关键词
		String[] keywordArray = keywords.split("[\\s,，]+");
		List<String> keywordList = Arrays.asList(keywordArray);

		// 查找包含这些关键词的需求
		List<Issue> candidates = issueMapper.selectByKeywords(keywordList, projectId);

		// 如果没有项目限制，返回前N个结果
		if (projectId == null) {
			return candidates.stream().limit(limit != null ? limit : 10).collect(Collectors.toList());
		}

		// 有项目限制，也需要限制结果数量
		return candidates.stream().limit(limit != null ? limit : 10).collect(Collectors.toList());
	}

	/**
	 * 实时计算相似需求
	 */
	private List<Issue> calculateSimilarIssues(Issue sourceIssue, Integer limit) {
		List<Issue> candidateIssues = issueMapper.selectCandidatesForSimilarity(sourceIssue.getId(),
				sourceIssue.getProjectId());

		List<SimilarIssue> similarIssues = new ArrayList<>();

		for (Issue candidate : candidateIssues) {
			SimilarityResult result = calculateSimilarity(sourceIssue, candidate);

			if (result.getScore() >= SIMILARITY_THRESHOLD) {
				similarIssues.add(new SimilarIssue(candidate, result.getScore(), result.getReasons()));
			}
		}

		// 按相似度排序
		similarIssues.sort((a, b) -> Double.compare(b.getScore(), a.getScore()));

		// 限制结果数量
		List<Issue> result = similarIssues.stream().limit(limit != null ? limit : 5).map(SimilarIssue::getIssue)
				.collect(Collectors.toList());

		// 异步缓存结果
		new Thread(() -> calculateAndCacheSimilarities(sourceIssue.getId())).start();

		return result;
	}

	/**
	 * 计算两个需求的相似度（基于HanLP优化）
	 */
	private SimilarityResult calculateSimilarity(Issue source, Issue target) {
		double titleSimilarity = 0.0;
		double descriptionSimilarity = 0.0;
		double keywordSimilarity = 0.0;
		double categorySimilarity = 0.0;
		double trackerSimilarity = 0.0;
		double prioritySimilarity = 0.0;

		StringBuilder reasons = new StringBuilder();

		// 标题相似度（权重最高）
		if (StringUtils.hasText(source.getSubject()) && StringUtils.hasText(target.getSubject())) {
			titleSimilarity = HanLPUtil.calculateSimilarity(source.getSubject(), target.getSubject());
			if (titleSimilarity > 0.5) {
				reasons.append("标题相似度高;");
			}
		}

		// 描述相似度（先清理HTML标签）
		if (StringUtils.hasText(source.getDescription()) && StringUtils.hasText(target.getDescription())) {
			descriptionSimilarity = HanLPUtil.calculateSimilarity(HtmlUtils.delHTMLTag(source.getDescription()),
					HtmlUtils.delHTMLTag(target.getDescription())) * 0.8;
			if (descriptionSimilarity > 0.4) {
				reasons.append("描述内容相似;");
			}
		}

		// 关键词相似度（新增，描述字段已自动清理HTML）
		if (StringUtils.hasText(source.getSubject()) && StringUtils.hasText(target.getSubject())
				&& StringUtils.hasText(source.getDescription()) && StringUtils.hasText(target.getDescription())) {
			keywordSimilarity = HanLPUtil.calculateRequirementSimilarity(source.getSubject(),
					HtmlUtils.delHTMLTag(source.getDescription()), target.getSubject(),
					HtmlUtils.delHTMLTag(target.getDescription()));
			if (keywordSimilarity > 0.3) {
				reasons.append("关键词相似;");
			}
		}

		// 类别相似度
		if (source.getCategoryId() != null && source.getCategoryId().equals(target.getCategoryId())) {
			categorySimilarity = 0.3;
			reasons.append("同一类别;");
		}

		// 跟踪类型相似度
		if (source.getTrackerId() != null && source.getTrackerId().equals(target.getTrackerId())) {
			trackerSimilarity = 0.2;
			reasons.append("同一跟踪类型;");
		}

		// 优先级相似度
		if (source.getPriorityId() != null && source.getPriorityId().equals(target.getPriorityId())) {
			prioritySimilarity = 0.1;
		}

		// 计算总相似度（加权平均）
		double totalSimilarity = titleSimilarity * 0.3 + descriptionSimilarity * 0.25 + keywordSimilarity * 0.2
				+ categorySimilarity * 0.1 + trackerSimilarity * 0.1 + prioritySimilarity * 0.05;

		return new SimilarityResult(totalSimilarity, reasons.toString());
	}

	/**
	 * 更新需求的关键词和标签
	 */
	private void updateKeywordsAndTags(Issue issue) {
		Set<String> keywords = new HashSet<>();

		// 从标题中提取关键词
		if (StringUtils.hasText(issue.getSubject())) {
			keywords.addAll(extractKeywords(issue.getSubject()));
		}

		// 从描述中提取关键词
		if (StringUtils.hasText(issue.getDescription())) {
			keywords.addAll(extractKeywords(HtmlUtils.delHTMLTag(issue.getDescription())));
		}

		// 添加类别标签
		StringBuilder categoryTags = new StringBuilder();
		if (issue.getCategoryName() != null) {
			categoryTags.append(issue.getCategoryName()).append(";");
		}
		if (issue.getTrackerName() != null) {
			categoryTags.append(issue.getTrackerName()).append(";");
		}
		if (issue.getPriorityName() != null) {
			categoryTags.append(issue.getPriorityName()).append(";");
		}

		// 更新到数据库
		issue.setKeywords(String.join(",", keywords));
		issue.setCategoryTags(categoryTags.toString());
		issueMapper.updateIssue(issue);
	}

	/**
	 * 从文本中提取关键词（基于HanLP优化）
	 */
	private Set<String> extractKeywords(String text) {
		if (text == null || text.trim().isEmpty()) {
			return new HashSet<>();
		}

		// 使用HanLP提取技术相关关键词
		List<String> keywords = HanLPUtil.extractTechnicalKeywords(text, 20);

		return new HashSet<>(keywords);
	}

	/**
	 * 相似度结果内部类
	 */
	private static class SimilarityResult {
		private final double score;
		private final String reasons;

		public SimilarityResult(double score, String reasons) {
			this.score = score;
			this.reasons = reasons;
		}

		public double getScore() {
			return score;
		}

		public String getReasons() {
			return reasons;
		}
	}

	/**
	 * 相似需求内部类
	 */
	private static class SimilarIssue {
		private final Issue issue;
		private final double score;
		private final String reasons;

		public SimilarIssue(Issue issue, double score, String reasons) {
			this.issue = issue;
			this.score = score;
			this.reasons = reasons;
		}

		public Issue getIssue() {
			return issue;
		}

		public double getScore() {
			return score;
		}

		public String getReasons() {
			return reasons;
		}
	}
}